Skip to content

feat(cli): expand fast_provision experiment to images + docker + sandbox#3398

Merged
la14-1 merged 3 commits intoOpenRouterTeam:mainfrom
AhmedTMM:feat/restore-feature-flags
May 9, 2026
Merged

feat(cli): expand fast_provision experiment to images + docker + sandbox#3398
la14-1 merged 3 commits intoOpenRouterTeam:mainfrom
AhmedTMM:feat/restore-feature-flags

Conversation

@AhmedTMM
Copy link
Copy Markdown
Collaborator

@AhmedTMM AhmedTMM commented May 8, 2026

Summary

The PostHog `fast_provision` flag is already wired via `shared/feature-flags.ts` and currently bundles `images` for the `test` variant. This PR expands the test variant to the full provisioning-speed stack:

  • images — pre-built DO marketplace images (cloud-side faster boot)
  • docker — Docker CE host image on Hetzner/GCP (cloud-side faster boot)
  • sandbox — local agents run in a Docker container (local-side faster boot)

Users who explicitly pass `--beta` or `--fast` still take precedence and skip the experiment bucket. `$feature_flag_called` exposure events continue to capture for both variants so PostHog can compute conversion across the broader bundle.

Heads-up: known sandbox gap

`pullAndStartContainer` in `packages/cli/src/local/local.ts:533` runs `docker run` with no volume mount. When the experiment routes a user into the test variant on `local` for a coding agent (claude/codex/cursor/etc.), the container cannot see their working directory — the primary use case breaks.

Two options before flipping the flag on at PostHog:

  1. Recommended — add `-v "$(pwd)":/workspace -w /workspace` to `pullAndStartContainer` for coding agents. One-liner, makes sandbox actually usable.
  2. Alternative — exclude coding agents from the sandbox variant; keep it limited to openclaw/hermes where containerization without mount is fine.

Either way, this PR ships the bundle change cleanly; the volume-mount fix is small enough to land separately or as a follow-up commit on this branch — your call.

Test plan

  • `bun test src/tests/feature-flags.test.ts` — 11/11 pass
  • `bunx @biomejs/biome check src/` — clean
  • Smoke test: `SPAWN_FEATURE_FLAGS_DISABLED=1 spawn claude local` (control path) → behaves as today
  • Smoke test: force test variant, verify `SPAWN_BETA=images,docker,sandbox`
  • Decide on volume-mount before flipping flag at PostHog

🤖 Generated with Claude Code

Builds on the existing PostHog `fast_provision` flag (already wired via
shared/feature-flags.ts). The `test` variant now bundles the full
provisioning-speed stack rather than images alone:

  - images:  pre-built DO marketplace images (cloud-side faster boot)
  - docker:  Docker CE host image on Hetzner/GCP (cloud-side faster boot)
  - sandbox: local agents run in a Docker container (local-side faster boot)

Users who explicitly pass --beta or --fast still take precedence and skip
the experiment bucket. Exposure events are still captured for both
variants so PostHog can compute conversion across the broader bundle.

Bumps CLI to 1.0.39.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@AhmedTMM AhmedTMM marked this pull request as ready for review May 9, 2026 05:34
@la14-1
Copy link
Copy Markdown
Member

la14-1 commented May 9, 2026

Review

Verified the diff against the codebase. The mechanics of the change are clean — only the experiment bundle widens, exposure capture and --beta/--fast precedence are unchanged, version bump is correct. But I'd hold this PR until the sandbox volume-mount lands, ideally on the same branch.

Blocker: sandbox ships broken for the primary use case

You flagged this in the PR description, but I want to underscore the consequence: once 1.0.39 is released, every user bucketed into fast_provision=test for spawn claude local (or codex/cursor/kilo/opencode) gets an agent in a container that cannot see their working directory.

packages/cli/src/local/local.ts:503-542pullAndStartContainer runs:

docker run -d --name <name> <image>

No -v, no -w. dockerInteractiveSession (lines 544-557) also docker execs without a workdir. Coding agents are the headline use case for spawn, so the test variant would regress them silently for ~50% of unopted users.

There is no in-code gate that says "don't include sandbox until PostHog is flipped on" — once this is merged + auto-updated, the bundle is live as soon as the flag is enabled, and that decision lives outside this repo.

Recommendation: land Option 1 (the -v \"\$(pwd)\":/workspace -w /workspace one-liner) on this branch before merging. That's small enough to keep this as a single coherent PR.

Other concerns (non-blocking)

  1. Inconsistency with --fast (packages/cli/src/index.ts:966-968). --fast currently expands to tarball, images, parallel, docker — explicitly not sandbox. The test variant now ships a strictly different bundle than the user-facing fast flag. Either align them (add sandbox to --fast, or drop it from the experiment) or document why they intentionally diverge. The current state means a user who reads the docs and types --fast gets a different experience than a user silently bucketed to test.

  2. No unit test for the bundle. feature-flags.test.ts only covers getFeatureFlag's return values. There's no test that asserts variant === \"test\" results in SPAWN_BETA containing images,docker,sandbox. A small spy on betaFeatures after main() would prevent regressions when someone tweaks this list later.

  3. docker + sandbox interaction is untested. docker is a cloud-side flag (Hetzner/GCP host image); sandbox is local-only. They shouldn't conflict in practice (different cloud paths), but the experiment now bundles both and we have no test that exercises the combination on either path. Low risk, but worth a sentence in the PR body confirming you've reasoned through it.

Approving criteria

  • Add -v + -w to pullAndStartContainer (and consider dockerInteractiveSession) OR drop sandbox from the bundle for now
  • One unit test asserting the test-variant bundle composition
  • Brief note on --fast vs experiment-bundle divergence

Once the sandbox path actually works for coding agents, this is a clean ship.

Filed from Slack by SPA

Addresses review feedback on the fast_provision experiment expansion:

- Align `--fast` with the experiment `test` variant. Previously --fast
  pushed [tarball, images, parallel, docker] (no sandbox) while the
  silent A/B pushed [images, docker, sandbox]. Add `sandbox` to --fast
  so the explicit user opt-in exercises the same surface as the silent
  experiment, plus the speed-ups outside the experiment scope.

- Extract the experiment bundle into a pure `expandFastProvisionVariant`
  helper in shared/feature-flags.ts so the bundle composition is
  testable in isolation from main() arg parsing. Drop-in replacement
  in index.ts; behavior unchanged for the test variant.

- Add unit tests pinning the bundle: test variant -> [images, docker,
  sandbox], control -> [], unknown variants -> [] (fail-closed). These
  guard against silent drift when someone tweaks the list later.

- Bump CLI 1.0.39 -> 1.0.40 per the version-on-every-cli-change rule.

Verified: bunx biome check src/ clean, bun test 2188/2188 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@la14-1
Copy link
Copy Markdown
Member

la14-1 commented May 9, 2026

Follow-up commit pushed: 8f87330

Acknowledged the cwd-isolation-is-intentional clarification — dropped that concern. Pushed a follow-up commit addressing the three non-blocking items from my review.

What changed

1. Aligned `--fast` with the experiment bundle (`packages/cli/src/index.ts`)

Before: `--fast` → `[tarball, images, parallel, docker]`, experiment test variant → `[images, docker, sandbox]`. Sandbox was reachable only via the silent A/B or via `--beta sandbox` directly, not via the explicit `--fast` opt-in.

After: `--fast` → `[tarball, images, parallel, docker, sandbox]`. The explicit opt-in now exercises the same surface as the experiment plus the speed-ups outside the experiment's scope. Comment updated to note the alignment is intentional and to keep both bundles in sync.

2. Extracted bundle into a testable helper (`packages/cli/src/shared/feature-flags.ts`)

New `expandFastProvisionVariant(variant: string): readonly string[]` lives next to `getFeatureFlag`. `index.ts` now does:

const variant = getFeatureFlag(\"fast_provision\", \"control\");
const variantStr = isString(variant) ? variant : \"control\";
betaFeatures.push(...expandFastProvisionVariant(variantStr));

The `isString` narrowing is required because flags can be string OR boolean. Pure function, drop-in replacement, behavior unchanged for the test variant.

3. Added unit tests pinning the bundle (`packages/cli/src/tests/feature-flags.test.ts`)

expandFastProvisionVariant(\"test\")     [\"images\", \"docker\", \"sandbox\"]
expandFastProvisionVariant(\"control\") → []
expandFastProvisionVariant(\"\")        → []
expandFastProvisionVariant(\"rollout\") → []

Guards against silent drift if someone tweaks the list. Was 11 tests in the suite, now 14.

4. Docker + sandbox interaction (verified, no code change needed)

Confirmed by reading the cloud entry points: `hetzner/main.ts` and `gcp/main.ts` only check `betaFeatures.includes("docker")`; `local/main.ts` only checks `betaFeatures.includes("sandbox")`; `digitalocean/main.ts` only checks `"images"`. A given `spawn ` run picks exactly one cloud, so the flags never combine in the same execution path. The "untested combination" concern is moot — they're orthogonal.

5. Version bump: 1.0.39 → 1.0.40, per `.claude/rules/cli-version.md`.

Verification

  • `bunx @biomejs/biome check src/` → clean
  • `bun test` → 2188/2188 pass (was 2185 + 3 new bundle tests)
  • `bun test src/tests/feature-flags.test.ts` → 14/14 pass

Diff is +59/-7 across 4 files.

Filed from Slack by SPA

My previous commit (8f87330) added `sandbox` to --fast to align it with
the experiment test variant. That was wrong — --fast is unrelated to
the fast_provision experiment, has its own meaning, and shouldn't
inherit changes from the experiment bundle.

- Restore --fast to [tarball, images, parallel, docker] (its prior set).
- Drop the cross-reference comments tying --fast to the experiment.
- Keep expandFastProvisionVariant() and its unit tests intact — the
  experiment bundle still lives in feature-flags.ts as a testable
  pure helper, just no longer claims alignment with --fast.
- Bump CLI 1.0.40 -> 1.0.41.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@la14-1
Copy link
Copy Markdown
Member

la14-1 commented May 9, 2026

Reverted --fast change in 12f7063

Misread your scope on the prior commit — pushed a revert.

`--fast` is back to `[tarball, images, parallel, docker]` (unchanged from before). The experiment bundle in `expandFastProvisionVariant` stays at `[images, docker, sandbox]` and is reachable only via the silent `fast_provision` flag bucketing or via explicit `--beta sandbox` / `--beta docker` / `--beta images`.

What survives from the prior commit:

  • `expandFastProvisionVariant(variant)` helper in `shared/feature-flags.ts`
  • 3 unit tests pinning the bundle composition (test → 3 features, control/unknown → empty)
  • `index.ts` calling the helper instead of inline-ing the list

Updated the helper's docstring to say it's experiment-only, no relation to `--fast`.

Bumped 1.0.40 → 1.0.41. Biome clean, 2188/2188 tests pass.

Filed from Slack by SPA

Copy link
Copy Markdown
Member

@la14-1 la14-1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All checks green; reverted the --fast scope creep; experiment bundle stays scoped to its 3 features. LGTM.

@la14-1 la14-1 merged commit af8ac24 into OpenRouterTeam:main May 9, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants